﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace NetworkSimulator
{
    public class OfflinePhase_DORA : DisjointPaths
    {
        protected IEList ieList = IEList.instance();

        // define PPV array
        private int[,] ppv;

        public int[,] PPV
        {
            get { return ppv; }
        }

        private int[] ppv_s;

        // Init List Link to get All link of map
        private List<Link> linkList = new List<Link>();


        public static OfflinePhase_DORA singletonOfflineDORA;

        private int index(Link link)
        {
            return linkList.FindIndex(x => x.Source.Id == link.Source.Id && x.Destination.Id == link.Destination.Id);
        }

        // DORA offline phase
        public OfflinePhase_DORA()
        {
            linkList = map.Links;
            
            // Init ppv & ppv_s array
            ppv_s = new int[map.Links.Count];
            ppv = new int[ieList.IngressEgressList.Count, map.Links.Count];

            for (int i = 0; i < ieList.IngressEgressList.Count; i++)
            {
                for (int j = 0; j < map.Links.Count; j++)
                {
                    ppv_s[j] = 0;
                    ppv[i, j] = 0;

                    //Console.Write(ppv[i, j]);
                }
            }

            // Find Disjoint Paths foreach IE
            int k = 0;
            foreach (IngressEgress ie in ieList.IngressEgressList)
            {
                // If had at least one path from source to destination
                while (BFS(nodes[ie.Ingress.Id], nodes[ie.Egress.Id]).Links.Count > 0)
                {
                    // List of Disjoint Paths
                    List<Link> listDPLink = new List<Link>();
                    listDPLink = GetDisjointPaths(nodes[ie.Ingress.Id], nodes[ie.Egress.Id]);

                    foreach (var p in listDPLink)
                    {
                        int j = index(p);
                        // If link of Disjoint Paths in IEList ppv = -1
                        ppv[k, j] = -1;

                        // increase 1 unit in ppv_s array
                        ppv_s[j] += 1;
                    }
                }

                // reset map for find Disjoint Paths of next IEList
                this.Renew();
                k++;
            }

            
            for (int i = 0; i < linkList.Count; i++)
            {
                // Only for Link in Disjoint Path of IEList
                if (ppv_s[i] == 0) continue;

                for (int j = 0; j < ieList.IngressEgressList.Count; j++)
                {
                    // If pvv = 0. Set pvv[][] = ppvs[], else pvv[][] =  ppvs[] - 2
                    if (ppv[j, i] == 0)
                        ppv[j, i] = ppv_s[i];
                    else
                        ppv[j, i] = ppv_s[i] - 2;
                }
            }

            // Find max min and caculator detal
            int max = (from int v in ppv select v).Max();
            int min = (from int v in ppv select v).Min();
            int delta = max - min;

            // Nomalized ppv based on pvv & ppvs array
            for (int i = 0; i < linkList.Count; i++)
            {
                for (int j = 0; j < ieList.IngressEgressList.Count; j++)
                {
                    ppv[j, i] = (ppv[j, i] - (-1)) * 1000 / delta;
                }
            }
        }

        // Synchronize object
        public static object lockingObject = new object();


        public static OfflinePhase_DORA instance()
        {
            if (singletonOfflineDORA == null)
            {
                lock (lockingObject)
                {
                    if (singletonOfflineDORA == null)
                        singletonOfflineDORA = new OfflinePhase_DORA();
                }
            }
            return singletonOfflineDORA;
        }
    }
}
